#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <lua_wrap.h>

#include <utils.h>

bool LuaWrap::load(const char *fn)
{
    if (_L)
        lua_close(_L);

    _L = lua_open();

    if (_L == NULL) {
        message(MSG_LEVEL_ERROR, "lua open failed: %s\n", strerror(errno));
        return false;
    }

    _fn = fn;
    if (luaL_loadfile(_L, fn)) {
        message(MSG_LEVEL_ERROR, "load lua file `%s' failed: %s\n",
                fn, lua_tostring(_L, -1));
        return false;
    }

    luaL_openlibs(_L);

    return true;
}

bool LuaWrap::run()
{
    if (_L == NULL)
        return false;

    int r = setjmp(_jmp);

    if (r == 0) {
        if (lua_pcall(_L, 0, LUA_MULTRET, 0)) {
            message(MSG_LEVEL_ERROR, "run lua file `%s' failed: %s\n",
                    _fn.c_str(), lua_tostring(_L, -1));
            return false;
        }
    }
    else {
    }

    return true;
}

bool LuaWrap::run_script_function(const char *func,
                                  LuaArgs&    args,
                                  LuaArgs&    rets)
{
    if (_L == NULL)
        return false;

    lua_getglobal(_L, func);

    if (!lua_isfunction(_L, -1)) {
        lua_pop(_L, 1);
        message(MSG_LEVEL_ERROR, "`%s' not function in script file `%s'\n",
                func, _fn.c_str());
        return false;
    }

    int i;
    for (i = 0; i < (int)args.size(); i++) {
        LuaArg& arg = args[i];

        if (arg._type == LUA_TYPE_STR) {
            lua_pushstring(_L, arg._str.c_str());
        }
        else if (arg._type == LUA_TYPE_INT) {
            lua_pushnumber(_L, arg._int);
        }
        else
            lua_pushnil(_L);
    }

    if (lua_pcall(_L, args.size(), rets.size(), 0)) {
        message(MSG_LEVEL_ERROR,
                "call function `%s' failed: %s, fn = `%s'\n",
                func, lua_tostring(_L, -1), _fn.c_str());
        lua_pop(_L, 1);
        return false;
    }

    for (i = 0; i < (int)rets.size(); i++) {
        LuaArg& arg = rets[i];

        int stk_idx = i - (int) rets.size();

        if (arg._type == LUA_TYPE_STR) {
            if (!lua_isstring(_L, stk_idx)) {
                message(MSG_LEVEL_ERROR,
                        "ret type error, need string at %d ret, fn = `%s', func = `%s'\n",
                        i, _fn.c_str(), func);
                lua_pop(_L, rets.size());
                return false;
            }
            arg._str = lua_tostring(_L, stk_idx);
        }
        else if (arg._type == LUA_TYPE_INT) {
            if (!lua_isnumber(_L, stk_idx)) {
                message(MSG_LEVEL_ERROR,
                        "ret type error, need number at %d ret, fn = `%s', func = `%s'\n",
                        i, _fn.c_str(), func);
                lua_pop(_L, rets.size());
                return false;
            }
            arg._int = lua_tonumber(_L, stk_idx);
        }
    }

    if (rets.size() > 0) {
        lua_pop(_L, rets.size());
    }

    return true;
}
